/**
 * Company:wz
 * Title:WzDataChannelHelper.java
 * Description:
 * Date:2016年6月13日下午4:53:56
 * author:wei.liang 
 * Version:V1.0
 */

package com.wz.datachannel.netty;

import java.util.Iterator;
import java.util.List;
import java.util.TimerTask;

import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.wizhong.localsvr.client.JShiTime;
import com.wizhong.localsvr.client.JShiTime.TimeCall;
import com.wizhong.localsvr.dp.ChannelErrorCode;
import com.wz.datachannel.app.AppContext;
import com.wz.datachannel.app.LocalData;
import com.wz.datachannel.common.GlobalConstant;
import com.wz.datachannel.interfaces.IGetSerListener;
import com.wz.datachannel.interfaces.IGetSerListener.RouteAddr;
import com.wz.datachannel.interfaces.OnNettyClientManagerEvent;
import com.wz.datachannel.interfaces.OnWzDataChannelEvent;
import com.wz.datachannel.model.BaseData;
import com.wz.datachannel.model.UserInfo;
import com.wz.datachannel.model.VerifyBean;
import com.wz.datachannel.model.protobuf.WznetDpBase;
import com.wz.datachannel.model.protobuf.WznetDpBase.wznet_dp_base;
import com.wz.datachannel.model.protobuf.WznetDpBase.wznet_dp_login_reply;
import com.wz.datachannel.model.protobuf.WznetDpBase.wznet_dp_login_request;
import com.wz.datachannel.util.FastJsonUtil;
import com.wz.datachannel.util.Utils;
import com.wz.datachannel.util.log4j.Log4jManager;
import com.wz.datachannel.view.VerifyDealActivity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import io.netty.util.internal.ConcurrentSet;

/** 
 * @Description
 * @author wei.liang 
 * @Date 2016年6月13日下午4:53:56
 */
public class WzDataChannelHelper {
	private Logger mLog = Log4jManager.getInstance();

	private static WzDataChannelHelper mInstance = null;
	private Context mContext = null;
	private OnWzDataChannelEvent mCallBack = null;

	private SerConnStatus mSerConnStatus = SerConnStatus.CONNECT_NOT;

	private ConcurrentSet<Integer> mRequstLoginList = new ConcurrentSet<Integer>();// 请求登录的业务列表

	private NettyHelper mNettyHelper = null;

	private String mUserInfo = null;
	private List<RouteAddr> mSerRouteList;//服务器地址

	private JShiTime mJShiTimer = new JShiTime();

	private WzDataChannelHelper(Context context, OnWzDataChannelEvent callBack) {
		this.mContext = context;
		this.mCallBack = callBack;
		this.mNettyHelper = new NettyHelper(mContext, onNettyClienEvent);
		setNettyConnThrdSleepTime(0);
		setNettyConnThrdStart();
	}

	public synchronized static WzDataChannelHelper getInstance(Context context, OnWzDataChannelEvent callBack) {
		if (null == mInstance) {
			mInstance = new WzDataChannelHelper(context, callBack);
		}
		return mInstance;
	}

	/**
	 * 登录
	 * 
	 * @author wei.liang
	 */
	public synchronized void login(Integer serverCode) {
		if (getIsForceMode()) {//强制模式下，延时通知业务登录失败
			onLoginFailedDelay(serverCode, mErrCode, mErrMsg);
		} else if (SerConnStatus.CONNECT_NOT == getConnStatus()) {// 未连接
			mRequstLoginList.add(serverCode);
			mRequestLogin = true;
			setNettyConnThrdSleepTime(0);
			setNettyConnThrdStart();
		} else if (SerConnStatus.CONNECT_ING == getConnStatus() || SerConnStatus.CONNECT_FAILED == getConnStatus()) {//正在连接||连接失败
			mRequestLogin = true;
			mRequstLoginList.add(serverCode);
		} else if (SerConnStatus.CONNECT_OK == getConnStatus() || SerConnStatus.LOGIN_ING == getConnStatus()) {//正在登录
			mRequstLoginList.add(serverCode);
		} else if (SerConnStatus.LOGIN_OK == getConnStatus()) {// 已登录
			loginBusiness(serverCode);
		}
	}

	/**
	 * 关闭退出
	 * @author wei.liang
	 */
	public void onDestory() {
		logoutChannel();
		//mCallBack = null;
		if (null != mNettyHelper) {
			mNettyHelper.close();
		}
	}

	/**
	 * 登出通道
	 * @author wei.liang
	 */
	private void logoutChannel() {
		sendData(true, 0, GlobalConstant.COMMAND_LOGOUT_REQUEST, null);
	}

	public void sendRoadData(Integer serverCode, ByteString value) {
		sendData(true, serverCode, GlobalConstant.COMMAND_BUSINESS_DATA, value);
	}

	private TimerTask mLoginChannelTask = null;

	/**
	 * 客户端登录
	 * 通道登录时，不附带业务代码
	 * @author wei.liang
	 */
	private void loginChannel() {
		setConnStatus(SerConnStatus.LOGIN_ING);

		WznetDpBase.wznet_dp_login_request.Builder loginRequest = wznet_dp_login_request.newBuilder();
		loginRequest.setUserID(LocalData.userId);
		loginRequest.setPassWord(LocalData.userPasswd);
		loginRequest.setAreaCode("");
		loginRequest.setVerCode(LocalData.VERSION);
		loginRequest.setVersion(LocalData.VERSION_NAME);
		loginRequest.setSysVersion(LocalData.SYS_VERSION + "");
		loginRequest.setSysVerCode(LocalData.SYS_VERSION_NAME);
		loginRequest.setSysScreen(LocalData.WIDTH + "*" + LocalData.HEIGHT);
		loginRequest.setTerminalID(0);
		//loginRequest.setSupportServerCodes(serverCodes);
		loginRequest.setOtherInfo("");
		loginRequest.setTags(mContext.getPackageName());

		sendData(false, 0, GlobalConstant.COMMAND_LOGIN_CHANNEL_REQUEST, loginRequest.build().toByteString());

		mLoginChannelTask = mJShiTimer.startTask(new TimeCall() {

			@Override
			public void OnTime(String tag) {//登录通道超时
				try {
					mLog.info("登录通道超时..");
					mNettyHelper.close();
				} catch (Exception e) {
				}
			}
		}, "", 30000);
	}

	private void closeLoginChannelTimer() {
		if (null != mLoginChannelTask) {
			mLoginChannelTask.cancel();
			mLoginChannelTask = null;
		}
	}

	/**
	 * 业务登录
	 * 
	 * @param serverCode
	 */
	private void loginBusiness(final Integer serverCode) {
		sendData(true, serverCode, GlobalConstant.COMMAND_LOGIN_BUSINESS_REQUEST, null);
	}

	/**
	 * 业务登出
	 * 
	 * @param serverCode
	 */
	public void logoutBusiness(Integer serverCode) {
		mRequstLoginList.remove(serverCode);
		sendData(true, serverCode, GlobalConstant.COMMAND_LOGOUT_BUSINESS_REQUEST, null);
	}

	/**
	 * 授权登陆受控方应答
	 * @author wei 
	 * @param taskid
	 * @param isAgree
	 * @param message
	 */
	public void sendConfirmVerifyResponse(String taskid, boolean isAgree, String message) {
		try {
			org.json.JSONObject jsonobj = new org.json.JSONObject();
			jsonobj.put("taskid", taskid);
			if (isAgree) {
				jsonobj.put("confirm", 1);
				jsonobj.put("message", TextUtils.isEmpty(message) ? "同意" : message);
			} else {
				jsonobj.put("confirm", -1);
				jsonobj.put("message", TextUtils.isEmpty(message) ? "拒绝" : message);
			}
			sendData(false, 0, GlobalConstant.COMMAND_VERIFY_APPLY_ACK, ByteString.copyFromUtf8(jsonobj.toString()));
		} catch (Exception e) {
		}
	}

	/**
	 * 发送心跳请求
	 */
	private void sendHeartRequest() {
		sendData(true, 0, GlobalConstant.COMMAND_HEART_REQUEST, null);
	}

	/**
	 * 发送心跳回复
	 */
	private void sendHeartResponse() {
		sendData(true, 0, GlobalConstant.COMMAND_HEART_RESPONSE, null);
	}

	private boolean isNettyConnedOk() {
		return null != mNettyHelper && mNettyHelper.isActive();
	}

	/**
	 * 
	 * @author wei.liang 
	 * @param isRoadData 是否为业务数据
	 * @param serverCode
	 * @param commond
	 * @param value
	 */
	private int sendData(boolean isRoadData, Integer serverCode, int commond, ByteString value) {
		if (!isNettyConnedOk()) {
			return -1;
		}

		if (isRoadData && getConnStatus() != SerConnStatus.LOGIN_OK) {//路由数据仅在登录成功后才可发送
			return -1;
		}

		BaseData baseData = new BaseData();
		baseData.setUniqueID(1);
		baseData.setServerCode(serverCode);
		baseData.setCommand(commond);
		Object obj = null;
		if (null == value) {
			obj = build(baseData).build();
		} else {
			obj = build(baseData).setDataBuffer(value).build();
		}
		mLog.debug("[" + commond + "]," + obj);
		mNettyHelper.sendData(obj);

		return 1;
	}

	private WznetDpBase.wznet_dp_base.Builder build(BaseData data) {
		WznetDpBase.wznet_dp_base.Builder dp = wznet_dp_base.newBuilder();
		dp.setCommand(data.getCommand());
		dp.setUniqueID(data.getUniqueID());
		dp.setServerCode(data.getServerCode());
		return dp;
	}

	//=========Netty重连==========start===

	private NettyConnThread mNettyConnThrd;

	/**
	 * 设置线程初始休眠时间
	 * @author wei 
	 * @param sleepTime
	 */
	private synchronized void setNettyConnThrdSleepTime(long sleepTime) {
		if (null == mNettyConnThrd) {
			mNettyConnThrd = new NettyConnThread();
		}
		mNettyConnThrd.setSleepTime(sleepTime);
	}

	/**
	 * 重连线程启动
	 * @author wei
	 */
	private synchronized void setNettyConnThrdStart() {
		if (null == mNettyConnThrd) {
			mNettyConnThrd = new NettyConnThread();
			mNettyConnThrd.start();
		} else if (!mNettyConnThrd.isAlive()) {//未启动
			mNettyConnThrd.start();
		} else if (SyncStatus.wait == mNettyConnThrd.token.getStatus()) {
			synchronized (mNettyConnThrd.token) {
				mNettyConnThrd.token.notify();
			}
		}
	}

	/**
	 * 重连线程停止，仅当[Netty连接成功+通道登录成功]之后调用
	 * @author wei
	 */
	private synchronized void setNettyConnThrdStop() {
		if (null != mNettyConnThrd) {
			mNettyConnThrd.setThdStop();
			if (SyncStatus.wait == mNettyConnThrd.token.getStatus()) {
				synchronized (mNettyConnThrd.token) {
					mNettyConnThrd.token.notify();
				}
			}
			mNettyConnThrd = null;
		}
	}

	private boolean mIsForceMode = false;
	private int mErrCode = 0;
	private String mErrMsg = "";

	/**
	 * 设置强制模式
	 * 强制模式:不受理用户登录请求，根据上次错误代码，直接返回用户，假登录
	 * 自由模式：受理登录请求，
	 * @author wei 
	 * @param isForceMode true:强制模式，false，自由模式
	 */
	private synchronized void setForceMode(boolean isForceMode, int errCode, String msg) {
		this.mIsForceMode = isForceMode;
		this.mErrCode = errCode;
		this.mErrMsg = msg;
	}

	private synchronized boolean getIsForceMode() {
		return mIsForceMode;
	}

	private final long NETTY_CONNET_GAP = 1000 * 60 * 3;//netty客户端重连间隔 3分钟
	private final long NETTY_CONNET_CHECK_GAP = 1000 * 10;//netty重连线程检测间隔 10秒
	private final long NETTY_THD_INIT_SLEEP_TIME_DEFAULT = 1000 * 10;//重连线程 首次启动默认间隔时间
	private final int SLEEP_COUNT_LIMIT = (int) (NETTY_CONNET_GAP / NETTY_CONNET_CHECK_GAP);

	private boolean mRequestLogin = true;//请求登录标志

	class NettyConnThread extends Thread {
		long tInitSleepTime = NETTY_THD_INIT_SLEEP_TIME_DEFAULT;//重连线程 首次启动间隔时间
		int sleepCount = 0;

		boolean stopFlag = false;//线程停止标志

		public Token token = new Token();

		public void setSleepTime(long time) {
			//			mLog.debug("time = " + time);
			//			time = 5000;//测试

			tInitSleepTime = time > 0 ? time : 0;
		}

		private long getThdSleepTime() {
			long result = tInitSleepTime;
			tInitSleepTime = NETTY_THD_INIT_SLEEP_TIME_DEFAULT;
			return result;
		}

		public void setThdStop() {
			stopFlag = true;
		}

		private boolean isDoConnect() {
			if (mRequestLogin) {
				mRequestLogin = false;
				sleepCount = 0;
				return true;
			}

			sleepCount++;
			if (sleepCount >= SLEEP_COUNT_LIMIT) {
				sleepCount = 0;
				return true;
			}

			return false;
		}

		public void run() {
			while (!stopFlag && !AppContext.getInstance().isShutDown()) {
				token.setStatus(SyncStatus.exeu);
				setConnStatus(SerConnStatus.CONNECT_ING);
				HeartManager.resetCount();
				int i = 0;

				try {//线程唤醒后，先休眠一段时间，后运行
					long sleepTime = getThdSleepTime();
					mLog.debug("Netty连接线程启动,初始休眠时间： " + sleepTime);
					if (sleepTime > 0) {
						Thread.sleep(sleepTime);
					}
				} catch (Exception e) {
				}

				while (!stopFlag && !AppContext.getInstance().isShutDown()) {
					mLog.debug("正在尝试netty连接.." + i);
					setForceMode(false, 0, null);
					try {
						mNettyHelper.close();
					} catch (Exception e) {
					}

					while (!isDoConnect()) {
						try {
							sleep(NETTY_CONNET_CHECK_GAP);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}

					if (!LocalData.isUserInfoValid()) {
						mLog.debug("获取用户信息失败");
						onDataChannelClose(ChannelErrorCode.ERROR_FALI_CODE_ACCOUNT_NAME_PASS_ERROR, "获取用户信息失败");
						try {
							Thread.sleep(1000 * 60);
						} catch (Exception e) {
						}

					} else if (!Utils.isNetworkConnected(mContext)) {
						mLog.debug("网络暂时不可用");
						onDataChannelClose(ChannelErrorCode.ERROR_FALI_CODE_NETWORK_DISABLE, "网络暂时不可用");
						try {
							Thread.sleep(1000 * 20);
						} catch (Exception e) {
						}
					} else {
						RouteAddr routeAddr = getSerAddr(i++);
						if (null == routeAddr) {
							mLog.debug("无法获取服务器地址");
							onDataChannelClose(ChannelErrorCode.ERROR_FALI_CODE_NETWORK_DISABLE, "获取服务器信息失败");
							try {
								Thread.sleep(1000 * 60);
							} catch (Exception e) {
							}
						} else {
							mNettyHelper.doConnectSync(routeAddr.ip, routeAddr.port);//发起同步连接，等待连接成功
						}
					}

					if (isNettyConnedOk()) {//netty连接成功，跳出循环
						break;
					}
				}

				if (!stopFlag && !AppContext.getInstance().isShutDown()) {
					synchronized (token) {
						token.setStatus(SyncStatus.wait);
						i = 0;
						sleepCount = 0;
						mRequestLogin = false;
						try {
							token.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}

	/**
	 * 获取本次登录使用的ip和端口
	 * @author wei 
	 * @param i
	 * @return
	 */
	public RouteAddr getSerAddr(int i) {
		if (Utils.isListEmpty(mSerRouteList) && Utils.isNetworkConnected(mContext)) {//服务器获取
			AppContext.getInstance().getSerAddr(new IGetSerListener() {

				@Override
				public void onSuccess(List<RouteAddr> list) {
					mSerRouteList = list;
				}

				@Override
				public void onFailed(String errMsg) {
					mLog.debug("获取服务器地址失败," + errMsg);
				}
			});
		}

		RouteAddr routeAddr = null;
		try {
			int pos = i % mSerRouteList.size();
			routeAddr = mSerRouteList.get(pos);
			mSerRoutePos = pos;
		} catch (Exception e) {
		}
		return routeAddr;
	}

	private int mSerRoutePos = 0;

	/**
	 * 移除服务器地址
	 * @author wei
	 */
	private synchronized void removeThisSerAddr() {
		try {
			mSerRouteList.remove(mSerRoutePos);
		} catch (Exception e) {
		}
	}

	/**
	 * 回调通道断开
	 * @author wei 
	 * @param errCode
	 * @param msg
	 */
	private void onDataChannelClose(int errCode, String msg) {
		mRequstLoginList.clear();
		if (null != mCallBack) {
			mCallBack.onDataChannelClose(errCode, msg);
		}
	}

	/**
	 * 延时通知登录失败
	 * @author wei 
	 * @param serverCode
	 * @param errCode
	 * @param msg
	 */
	private void onLoginFailedDelay(final int serverCode, final int errCode, final String msg) {
		mJShiTimer.startTask(new TimeCall() {

			@Override
			public void OnTime(String tag) {
				if (null != mCallBack) {
					mCallBack.onLoginFailed(serverCode, errCode, msg);
				}
			}
		}, "", 10000);
	}

	private OnNettyClientManagerEvent onNettyClienEvent = new OnNettyClientManagerEvent() {

		@Override
		public void onConnectSucceed() {
			/**
			 * 1.设置状态为已连接 2检测是否有待登录的业务client 
			 */
			setConnStatus(SerConnStatus.CONNECT_OK);
			closeLoginChannelTimer();
			loginChannel();
		}

		@Override
		public void onConnectFailed() {
			setConnStatus(SerConnStatus.CONNECT_FAILED);
			closeLoginChannelTimer();
			setNettyConnThrdStart();
			onDataChannelClose(ChannelErrorCode.ERROR_FALI_CODE_CONNECT_OFF, "服务器连接已断开");
		}

		@Override
		public void onChannelIdle() {
			if (!HeartManager.isOverLimit()) {
				HeartManager.countAdd();
				sendHeartRequest();
			} else {
				setConnStatus(SerConnStatus.CONNECT_FAILED);
				closeLoginChannelTimer();
				onDataChannelClose(ChannelErrorCode.ERROR_FALI_CODE_CONNECT_OFF, "服务器心跳超时");
				//心跳超时，不设置为强制模式
				//重连线程不设置休眠

				try {
					mNettyHelper.close();
				} catch (Exception e) {
				}
			}
		}

		@Override
		public void onRcvData(Object msg) {
			HeartManager.resetCount();
			try {
				wznet_dp_base dp = (wznet_dp_base) msg;
				int command = dp.getCommand();
				switch (command) {
				case GlobalConstant.COMMAND_HEART_REQUEST:
					sendHeartResponse();
					break;
				case GlobalConstant.COMMAND_HEART_RESPONSE:
					break;
				case GlobalConstant.COMMAND_LOGIN_CHANNEL_RESPONSE:
					handlerLoginChannelResponse(dp);
					break;
				case GlobalConstant.COMMAND_LOGIN_BUSINESS_RESPONSE:
					handlerLoginBusinessResponse(dp);
					break;
				case GlobalConstant.COMMAND_LOGOUT_BUSINESS_RESPONSE:
					handlerLogoutBusinessResponse(dp);
					break;
				case GlobalConstant.COMMAND_SERVER_DISCONNECT:
					handlerServerDisconnectResponse(dp);
					break;
				case GlobalConstant.COMMAND_BUSINESS_DATA:
					if (null != mCallBack) {
						mCallBack.onRcvRoadData(dp.getServerCode(), dp.getDataBuffer());
					}
					break;
				case GlobalConstant.COMMAND_NTF_UPDATE_OWN_INFO:
					if (null != mCallBack) {
						mUserInfo = dp.getDataBuffer().toStringUtf8();
						mCallBack.onRcvUpdateUserInfo(mUserInfo);
					}
					break;
				case GlobalConstant.COMMAND_UPDATE_OWN_INFO_RESPONSE:
					//修改资料回复--daizg 2016-9-27
					handlerUpdateOwnInfoResponse(dp);
					break;
				case GlobalConstant.COMMAND_VERIFY_APPLY_NOTIFITION://帐号授权申请通知
					handlerVerifyLoginNtf(dp.getDataBuffer().toStringUtf8());
					break;
				default:
					mLog.info("unkown command:" + command);
					break;
				}
			} catch (Exception e) {
				e.printStackTrace();
				mLog.info("unable analysis data:" + msg);
			}
		}
	};

	/**
	 * 处理通道登录回复
	 * 2016.10.31:登录通道时，不预登业务
	 * @author wei.liang 
	 * @param dp
	 */
	private void handlerLoginChannelResponse(wznet_dp_base dp) {
		try {
			closeLoginChannelTimer();
			wznet_dp_login_reply rp = wznet_dp_login_reply.parseFrom(dp.getDataBuffer());

			mUserInfo = rp.getUserInfo();
			if (rp.getResultCode() == 1) {// 登录成功
				mLog.debug("通道登录成功:" + mUserInfo);
				setConnStatus(SerConnStatus.LOGIN_OK);
				setNettyConnThrdStop();
				//daizg 20160927:
				if (rp.hasTags()) {
					try {
						JSONObject jobj = JSON.parseObject(rp.getTags());
						fileUploadKey = jobj.getString("uploadkey");
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				//end..

				if (null != mCallBack) {//回调通知
					mCallBack.onDataChannelOpen();
				}

				try {
					Iterator<Integer> list = mRequstLoginList.iterator();
					while (list.hasNext()) {
						Integer serverCode = list.next();
						list.remove();
						loginBusiness(serverCode);
					}
				} catch (Exception e) {
				}

			} else {
				mLog.info("通道登录失败ERROR-CODE:" + rp.getResultCode() + " MSG:" + rp.getResultMsg());
				setConnStatus(SerConnStatus.CONNECT_FAILED);
				int errCode = 0;
				switch (rp.getResultCode()) {
				case -100://用户不存在
					errCode = ChannelErrorCode.ERROR_FALI_CODE_ACCOUNT_NAME_PASS_ERROR;
					setNettyConnThrdSleepTime(1000 * 60 * 30);//30分钟
					setForceMode(true, errCode, rp.getResultMsg());//设置为强制模式
					break;
				case -101://密码错误
					errCode = ChannelErrorCode.ERROR_FALI_CODE_ACCOUNT_NAME_PASS_ERROR;
					setNettyConnThrdSleepTime(1000 * 60 * 30);//30分钟
					setForceMode(true, errCode, rp.getResultMsg());//设置为强制模式
					break;
				case -102://服务器维护中
					errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_FAIL;
					removeThisSerAddr();
					break;
				case -103://服务器忙稍后重试
					errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_FAIL;
					removeThisSerAddr();
					break;
				case -104://服务器人数已满
					errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_FAIL;
					removeThisSerAddr();
					break;
				case -105://用户被禁止登录
					errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_FORBID;
					setNettyConnThrdSleepTime(1000 * 60 * 30);//30分钟
					setForceMode(true, errCode, rp.getResultMsg());//设置为强制模式
					break;
				case -106://当用户已在别处登录
					errCode = ChannelErrorCode.ERROR_FALI_CODE_ACCOUNT_USED_BY_OTHERS;
					setNettyConnThrdSleepTime(1000 * 30);//30秒钟
					setForceMode(true, errCode, rp.getResultMsg());//设置为强制模式
					break;
				case -107://业务类型服务器不支持
					errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_NOT_SUPPORT;
					setNettyConnThrdSleepTime(1000 * 60 * 30);//30分钟
					setForceMode(true, errCode, rp.getResultMsg());//设置为强制模式
					break;
				case -108://终端设备不支持
					errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_FAIL;
					setNettyConnThrdSleepTime(1000 * 60 * 30);//30分钟
					setForceMode(true, errCode, rp.getResultMsg());//设置为强制模式
					break;
				default://未知原因
					setNettyConnThrdSleepTime(1000 * 30);//30秒
					break;
				}
				onDataChannelClose(errCode, rp.getResultMsg());
				try {
					mNettyHelper.close();
				} catch (Exception e) {
				}
			}
		} catch (InvalidProtocolBufferException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 处理业务登录回复
	 * 
	 * @param dp
	 */
	private void handlerLoginBusinessResponse(wznet_dp_base dp) {
		try {
			wznet_dp_login_reply rp = wznet_dp_login_reply.parseFrom(dp.getDataBuffer());
			Integer serverCode = dp.getServerCode();

			if (rp.getResultCode() == 1) {// 业务登录成功
				mLog.debug(serverCode + ",业务登录成功:" + rp.getResultMsg());
				if (null != mCallBack) {
					mCallBack.onLoginSucceed(serverCode, mUserInfo);
				}
			} else {
				mLog.debug(serverCode + ",业务登录失败ERROR-CODE::" + rp.getResultCode() + " MSG:" + rp.getResultMsg());
				if (null != mCallBack) {
					int errCode = 0;
					switch (rp.getResultCode()) {
					case -1://当前已是登入状态
						errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_ALREADY_CONNECTED;
						break;
					case -2://禁止登录此业务
						errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_FORBID;
						break;
					case -107://业务类型服务器不支持
						errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_NOT_SUPPORT;
						break;
					default:
						break;
					}
					mCallBack.onLoginFailed(serverCode, errCode, rp.getResultMsg());
				}
			}
		} catch (InvalidProtocolBufferException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 处理服务器通知断开
	 * @author wei 
	 * @param dp
	 */
	private void handlerServerDisconnectResponse(wznet_dp_base dp) {
		try {
			String exitMsg = dp.getDataBuffer().toStringUtf8();
			String[] info = ChannelErrorCode.upPack(exitMsg);
			mLog.info("服务器断开通知：" + exitMsg);
			closeLoginChannelTimer();
			setConnStatus(SerConnStatus.CONNECT_FAILED);
			int errCode = 0;
			switch (Integer.valueOf(info[0])) {
			case 1://已经在其它地方登录
				errCode = ChannelErrorCode.ERROR_FALI_CODE_ACCOUNT_USED_BY_OTHERS;
				setNettyConnThrdSleepTime(1000 * 60 * 5);//5分钟
				setForceMode(true, errCode, info[1]);//设置为强制模式
				break;
			case 2://帐号禁止使用
				errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_FORBID;
				setNettyConnThrdSleepTime(1000 * 60 * 30);//30分钟
				setForceMode(true, errCode, info[1]);//设置为强制模式
				break;
			case 3://服务器强制关闭
				errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_OFF;
				setNettyConnThrdSleepTime(1000 * 30);//30秒
				break;
			default://未知原因
				setNettyConnThrdSleepTime(1000 * 30);//30秒
				break;
			}
			onDataChannelClose(errCode, info[1]);

			try {
				mNettyHelper.close();
			} catch (Exception e) {
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 处理业务登出回复
	 * 
	 * @param dp
	 */
	private void handlerLogoutBusinessResponse(wznet_dp_base dp) {
		try {
			wznet_dp_login_reply rp = wznet_dp_login_reply.parseFrom(dp.getDataBuffer());
			int serverCode = dp.getServerCode();
			int resultCode = rp.getResultCode();
			String resultMsg = rp.getResultMsg();
			mLog.debug(serverCode + ",业务登出回复:" + rp.getResultMsg());
			if (null != mCallBack) {
				int errCode = 0;
				switch (resultCode) {
				case 1://正常断开
					errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_OFF;
					break;
				case -1://该业务不是登录状态退出失败
					errCode = ChannelErrorCode.ERROR_FALI_CODE_CONNECT_OFF;
					break;
				case -2://业务被禁止使用
					errCode = ChannelErrorCode.ERROR_EXCEPTION_CODE_ACCOUNT_FORBID;
					break;
				default:
					break;
				}
				mCallBack.onLogoutResult(serverCode, errCode, resultMsg);
			}
		} catch (InvalidProtocolBufferException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 2016-09-27 daizheng -- 修改开始
	 * */
	public synchronized SerConnStatus getConnStatus() {
		return mSerConnStatus;
	}

	private synchronized void setConnStatus(SerConnStatus status) {
		this.mSerConnStatus = status;
	}

	public static enum SerConnStatus {
		CONNECT_NOT, // 未连接
		CONNECT_ING, // 正在连接
		CONNECT_OK, // 已连接
		CONNECT_FAILED, //连接失败
		LOGIN_ING, // 已连接，正在登录
		LOGIN_OK, // 已连接且已登录
	};

	/**
	 * 文件上传服务代码
	 */
	private String fileUploadKey = null;

	public String getFileUploadKey() {
		return this.fileUploadKey;
	}

	public UserInfo getUserInfo() {
		if (mUserInfo == null)
			return null;
		try {
			return JSON.parseObject(mUserInfo, UserInfo.class);
		} catch (Exception e) {
			;
		}
		return null;
	}

	public static interface ICallBackUpdateUserInfo {
		public void OnTimeOut();

		public void OnSucess();

		public void OnFail(String msg);
	}

	private ICallBackUpdateUserInfo mICallBackUpdateUserInfo = null;

	@SuppressLint("HandlerLeak")
	public int updateUserInfo(String jsonData, ICallBackUpdateUserInfo callback) {
		if (jsonData == null || mICallBackUpdateUserInfo != null)
			return 0;
		mICallBackUpdateUserInfo = callback;
		sendData(true, 0, GlobalConstant.COMMAND_UPDATE_OWN_INFO_REQUEST, ByteString.copyFromUtf8(jsonData));

		Handler mHandlerUpdateUserInfo = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == 2000) {
					if (mICallBackUpdateUserInfo != null) {
						mICallBackUpdateUserInfo.OnTimeOut();
						mICallBackUpdateUserInfo = null;
					}
				}
			}
		};
		mHandlerUpdateUserInfo.sendEmptyMessageDelayed(2000, 10 * 1000);//十秒钟超时计算
		return 1;
	}

	/**
	 * 资料修改回复
	 */
	private void handlerUpdateOwnInfoResponse(wznet_dp_base dp) {
		if (mICallBackUpdateUserInfo == null)
			return;
		try {
			String result = dp.getDataBuffer().toStringUtf8();
			String codes[] = result.split("#");
			if (codes[0].equals("1")) {
				//修改成功
				mICallBackUpdateUserInfo.OnSucess();
			} else {
				mICallBackUpdateUserInfo.OnFail(codes[1]);
			}
		} catch (Exception e) {
			if (mICallBackUpdateUserInfo != null) {
				mICallBackUpdateUserInfo.OnFail("结果处理时异常！");
			}
			e.printStackTrace();
		} finally {
			mICallBackUpdateUserInfo = null;
		}
	}

	/**
	 * 2016-09-27 daizhenguo -- 修改结束
	 */

	/**
	 * 处理授权登录通知
	 * @author wei 
	 * @param databuffer
	 */
	private void handlerVerifyLoginNtf(String databuffer) {
		mLog.debug("收到授权登录申请通知:" + databuffer);
		if (!TextUtils.isEmpty(databuffer)) {
			Intent intent = new Intent();
			intent.setClass(mContext, VerifyDealActivity.class);
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			intent.putExtra(VerifyDealActivity.INTENT_VERIFY_DATA, databuffer);
			mContext.startActivity(intent);
		}
	}
}

enum SyncStatus {
	wait, exeu,
}

class Token {
	private SyncStatus status;

	public Token() {
		setStatus(SyncStatus.exeu);
	}

	public SyncStatus getStatus() {
		return status;
	}

	public void setStatus(SyncStatus status) {
		this.status = status;
	}

}

class HeartManager {
	private static int mHeartSendCount = 0;
	private final static int MAX_HEART_SEND_LIMIT = 3;//心跳最大发送次数，大于时表示离线

	public static boolean isOverLimit() {
		return mHeartSendCount >= MAX_HEART_SEND_LIMIT;
	}

	public static boolean countAdd() {
		mHeartSendCount++;
		return isOverLimit();
	}

	public static void resetCount() {
		mHeartSendCount = 0;
	}

}